#!/usr/bin/env python
import logging, sys, time, os, wx, subprocess
from threading import Thread


class PingThread(Thread):
    def __init__(self, text_ctrl, btn_log, func_type=0):
        Thread.__init__(self)
        self.btn_log = btn_log
        self.text_ctrl = text_ctrl
        self.sentinel = True
        self.functype = func_type
        self.start()

    def run(self):
        if self.functype == 1:
            proc = subprocess.Popen(
                "python ./app/appYq.py", shell=True, stdout=subprocess.PIPE
            )
        elif self.functype == 2:
            proc = subprocess.Popen(
                "python ./app/appWea.py", shell=True, stdout=subprocess.PIPE
            )
        else:
            proc = subprocess.Popen(
                "python ./app/app.py", shell=True, stdout=subprocess.PIPE
            )

        while self.sentinel:
            line = proc.stdout.readline().decode("utf-8", "ignore")
            if line.strip() == "":
                pass
            else:
                wx.CallAfter(self.text_ctrl.write, line)

            if not line:
                self.btn_log.SetLabel("Start")
                break

        proc.kill()


# 自定义日志Handler来接收日志数据
class TextHandler(logging.Handler):
    def __init__(self):
        logging.Handler.__init__(self)
        self.ctrl = None

    def set_ctrl(self, ctrl):
        self.ctrl = ctrl

    def emit(self, record):
        if not self.ctrl == None:
            wx.CallAfter(self.ctrl.write, self.format(record) + "\n")


class LogUtils(object):
    log = None

    @staticmethod
    def sharedInstance(task_id):
        if LogUtils.log == None:
            LogUtils.log = LogUtils(task_id)
        return LogUtils.log

    def __init__(self, task_id):

        self.logger = logging.getLogger(task_id)
        self.level = logging.INFO
        self.fm = logging.Formatter(
            "%(asctime)s - %(filename)s - [line:%(lineno)-d] - %(levelname)s - %(message)s"
        )
        self.text_ctrl = None
        self.text_handler = TextHandler()

    def set_logger(self):
        # 设置日志目录和日志文件名称
        logs_dir = os.path.join("../logs/")
        if not os.path.exists(logs_dir):
            os.makedirs(logs_dir)
        # 文件对象
        fh = logging.FileHandler(
            os.path.join("../logs/", f'{time.strftime("%Y-%m-%d")}_win.log')
        )
        # 设置格式
        fh.setFormatter(self.fm)
        # logger添加文件输出流
        self.logger.addHandler(fh)

        # 输出到控制台，设置格式并添加标准输出流
        # sh = logging.StreamHandler()
        # sh.setFormatter(self.fm)
        # self.logger.addHandler(sh)

        # logger 添加文本处理器
        self.logger.addHandler(self.text_handler)

        # 设置日志输出等级
        self.logger.setLevel(self.level)
        self.logger.info(">>> Log Running")

    def info(self, s):
        self.logger.info(s)

    def set_ctrl_to_logging(self, text_ctrl):
        self.text_ctrl = text_ctrl
        if not self.text_handler == None:
            self.text_handler.set_ctrl(self.text_ctrl)


class HelloFrame(wx.Frame):
    """
    数据录入程序
    """

    def __init__(self, *args, **kw):
        # 确保调用父级的 __init__
        super(HelloFrame, self).__init__(*args, **kw, size=(600, 400))
        self.ping_thread = None
        # 创建面板
        pnl = wx.Panel(self)

        # 日志输出模块
        self.log_sizer = wx.GridBagSizer(5, 5)
        self.start_btn = wx.Button(pnl, -1, "Start", pos=(0, 0))
        self.timing_btn = wx.Button(pnl, -1, "Timing", pos=(0, 0))
        self.yq_btn = wx.Button(pnl, -1, "Yq", pos=(0, 0))
        self.wea_btn = wx.Button(pnl, -1, "Wea", pos=(0, 0))
        self.clear_btn = wx.Button(pnl, -1, "Clear", pos=(0, 0))
        self.exit_btn = wx.Button(pnl, -1, "Exit", pos=(0, 0))
        self.log_text = wx.TextCtrl(
            pnl, wx.ID_ANY, style=wx.TE_MULTILINE | wx.TE_READONLY
        )
        # 设置字体风格大小
        self.log_font = wx.Font(8, wx.MODERN, wx.NORMAL, wx.NORMAL, False, "Consolas")
        self.log_text.SetFont(self.log_font)
        self.main_logger = LogUtils.sharedInstance("win1")
        self.main_logger.set_ctrl_to_logging(self.log_text)
        self.main_logger.set_logger()
        # LogUtils.sharedInstance('1').test_log()

        # 绑定按钮事件
        self.Bind(wx.EVT_BUTTON, self.OnBtnLogClick, self.start_btn)
        self.Bind(wx.EVT_BUTTON, self.OnTimingClick, self.timing_btn)
        self.Bind(wx.EVT_BUTTON, self.OnYqBtnClick, self.yq_btn)
        self.Bind(wx.EVT_BUTTON, self.OnWeaBtnClick, self.wea_btn)
        self.Bind(wx.EVT_BUTTON, self.OnClearClick, self.clear_btn)
        self.Bind(wx.EVT_BUTTON, self.OnExitClick, self.exit_btn)
        # 设置定时任务启动按钮
        # 创建定时器,绑定一个定时器事件
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)

        # self.start_btn.SetDefault()
        self.log_sizer.Add(self.timing_btn, (0, 0), flag=wx.ALL, border=10)
        self.log_sizer.Add(self.clear_btn, (0, 2), flag=wx.ALL, border=10)
        self.log_sizer.Add(self.start_btn, (1, 3), flag=wx.ALL, border=10)
        self.log_sizer.Add(self.yq_btn, (2, 3), flag=wx.ALL, border=10)
        self.log_sizer.Add(self.wea_btn, (3, 3), flag=wx.ALL, border=10)
        self.log_sizer.Add(
            self.log_text, (1, 0), (10, 3), flag=wx.EXPAND | wx.ALL, border=10
        )
        self.log_sizer.Add(self.exit_btn, (9, 3), flag=wx.ALL, border=10)
        self.log_sizer.AddGrowableCol(1)
        self.log_sizer.AddGrowableRow(5)
        pnl.SetSizer(self.log_sizer)

        # menu bar 菜单栏
        self.makeMenuBar()

        # status bar 状态栏
        self.CreateStatusBar(4)
        self.SetStatusText("Version 1.0.2", 0)

    def makeMenuBar(self):
        """
        菜单栏 > 菜单组成 > 菜单项
        此方法构建一组菜单并绑定要调用的处理程序
        """

        # 文件菜单，含有欢迎和退出项
        fileMenu = wx.Menu()
        # 使用 "\t..." 定义触发快捷键
        helloItem = fileMenu.Append(-1, "&Hello...\tCtrl-H", "用来显示欢迎信息")
        fileMenu.AppendSeparator()

        # 使用wx自带的ID则不需要手动指定标签与提示信息
        exitItem = fileMenu.Append(wx.ID_EXIT)

        # 帮助菜单
        helpMenu = wx.Menu()
        aboutItem = helpMenu.Append(wx.ID_ABOUT)

        # 创建菜单栏并将两个菜单添加到其中。、
        # “&”定义了菜单项的“助记符”。带有下划线，可以从键盘触发。
        menuBar = wx.MenuBar()
        menuBar.Append(fileMenu, "&File")
        menuBar.Append(helpMenu, "&Help")

        # 菜单栏赋值
        self.SetMenuBar(menuBar)

        # 关联菜单项与触发事件
        self.Bind(wx.EVT_MENU, self.OnHello, helloItem)
        self.Bind(wx.EVT_MENU, self.OnExit, exitItem)
        self.Bind(wx.EVT_MENU, self.OnAbout, aboutItem)

    def OnExit(self, event):
        self.Close(True)

    def OnHello(self, event):
        """你好弹框"""
        wx.MessageBox("天若有情天亦老，Python正道是光芒", "欢迎")

    def OnAbout(self, event):
        """显示关于弹框"""
        wx.MessageBox("录入疫情与天气数据", "关于", wx.OK | wx.ICON_INFORMATION)

    def OnBtnLogClick(self, event):
        self.start_btn.SetLabel("Running...")
        self.ping_thread = PingThread(self.log_text, self.start_btn)

    def closeThread(self, event):
        if self.ping_thread:
            self.ping_thread.sentinel = False
            self.ping_thread.join()
        self.Destroy()

    def OnTimingClick(self, event):
        """
        开启定时任务，执行周期为开启时间后n小时
        """
        label = self.timing_btn.GetLabelText()
        if label == "Timing":
            # 开启操作
            self.timer.Start(1000)
            self.timing_btn.SetLabelText("Running")
        else:
            # 停止操作
            self.timer.Stop()
            self.SetStatusText("", 1)
            self.SetStatusText("", 2)
            self.timing_btn.SetLabelText("Timing")

    def OnTimer(self, event):
        """
        定时计算与定时任务处理函数
        """
        cur_stamp = int(time.time())
        str_time = time.localtime(cur_stamp)
        str_ymd = time.strftime("%Y-%m-%d", str_time)
        str_hms = time.strftime("%I:%M:%S", str_time)
        # 定时任务执行周期 seconds
        yq_unit = 60 * 60 * 10
        wea_unit = 60 * 60 * 3
        yq_hour_stamp = cur_stamp - (cur_stamp % yq_unit) + yq_unit
        wea_hour_stamp = cur_stamp - (cur_stamp % wea_unit) + wea_unit
        # 下次执行格式化时间
        # str_ymd2 = time.strftime("%H:%M:%S", time.localtime(hour_stamp))
        # 下次执行倒计时
        yq_sub_seconds = yq_hour_stamp - cur_stamp
        wea_sub_seconds = wea_hour_stamp - cur_stamp
        self.SetStatusText(str_ymd + " " + str_hms, 1)
        self.SetStatusText("Next Yq: " + str(yq_sub_seconds), 2)
        self.SetStatusText("Next Wea: " + str(wea_sub_seconds), 3)
        if yq_sub_seconds == 1:
            self.main_logger.info("yq Data Add Time: " + str_ymd + " " + str_hms)
            self.OnYqBtnClick(event)
        if wea_sub_seconds == 1:
            self.main_logger.info("wea Data Add Time: " + str_ymd + " " + str_hms)
            self.OnWeaBtnClick(event)

    def OnYqBtnClick(self, event):
        self.start_btn.SetLabel("Running...")
        self.ping_thread = PingThread(self.log_text, self.start_btn, 1)

    def OnWeaBtnClick(self, event):
        self.start_btn.SetLabel("Running...")
        self.ping_thread = PingThread(self.log_text, self.start_btn, 2)

    def OnClearClick(self, event):
        self.log_text.Clear()

    def OnExitClick(self, event):
        self.closeThread(event)


if __name__ == "__main__":
    app = wx.App()
    frm = HelloFrame(None, title="Data Entry")
    frm.Show()
    logo_icon = wx.Icon(name="assets/logos/wxpylogo.ico", type=wx.BITMAP_TYPE_ICO)
    frm.SetIcon(logo_icon)
    app.MainLoop()
